const { fork } = require("child_process");
const os = require("os");
const colors = require("colors");
// const vm = require("vm");
class Worker {
  taskQuery = [];
  /** @type{ChildProcess[]} */
  workerQuery = [];
  cpus = os.cpus().length;

  loopMonitor = 0;

  isMasterThreadExit = false;

  constructor() {
    //   console.log(`cpus:${colors.cyan(this.cpus)}`)
    for (let i = 0; i < this.cpus; i++) {
      this.createWorker();
    }
    this.events();
    this.eventLoop();
  }

  add(params) {
    this.taskQuery.push(params);
  }

  createWorker() {
    //保存fork返回的进程实例
    const worker = fork("./slice.js");
    //监听子进程exit事件
    worker.on("exit", (code, signal) => {
      if (code !== null && signal === null) {
        // console.log("worker:" + worker.pid + "exited");
        console.log(
          `worker:子进程${colors.bgCyan(worker.pid)}${colors.bgRed(
            "异常退出,已尝试重启中..."
          )}`
        );
        delete this.workerQuery[
          this.workerQuery.findIndex((i) => i.pid === worker.pid)
        ];
        this.createWorker();
      } else {
        console.log(`worker:子进程${colors.bgCyan(worker.pid)}正常退出`);
      }
    });

    worker.on("message", (mess) => {
      this.workerQuery.push(worker);
      console.log(
        `worker:子进程${colors.bgCyan(worker.pid)}收到消息:${colors.bgCyan(
          mess
        )}`
      );
    });
    this.workerQuery.push(worker);
    console.log("Create worker:" + colors.cyan(worker.pid));
  }

  events() {
    process.on("exit", () => {
      this.isMasterThreadExit = true;
      console.log(`worker:${colors.bgCyan(process.pid)}主线程退出`);
      for (const fork of this.workerQuery) {
        fork.kill();
      }

      clearInterval(this.loopMonitor);
    });
  }

  /**
   * @description 事件循环
   */
  eventLoop() {
    this.loopMonitor = setInterval(() => {
      if (!this.isMasterThreadExit) {
        //确保任务队列和线程池都有数据
        if (this.taskQuery.length !== 0 && this.workerQuery.length !== 0) {
          const task = this.taskQuery.shift();
          const fork = this.workerQuery.shift();
          // console.log(`task:${JSON.stringify(task)}`)
          // console.log(`fork:${fork}`)
          fork.send(task);
        }
      } else {
        clearInterval(this.loopMonitor);
      }
    }, 1000);
  }
}

module.exports = Worker;
